﻿using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System.Linq;
using System.Text;
using UnityEditor;
using UnityEngine.Assertions;
using System.Diagnostics;
using Debug = UnityEngine.Debug;
public class RefrenceMapBuilder
{
    public string Bin2TxtPath;
    public float checkMBThreshold = 10;
    public string ApplicationDataPath;
    public int procosserCount;

    /// <summary>
    /// U3D原始格式
    /// </summary>
    private List<string> nativeReadableExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };


    /// <summary>
    /// 存储在meta文件的后缀
    /// </summary>
    private List<string> metaStoreExtensions = new List<string>() { ".cs", ".fbx", ".shader" };

    public bool Vaild = false;

    private RefrenceMap m_curMap;
    private string[] m_totalFiles;

    public void MainThreadClenaUp()
    {
        m_curMap = null;
        m_totalFiles = null;
        Bin2TxtPath = EditorApplication.applicationContentsPath + "/Tools/binary2text.exe";
        Debug.Log(Bin2TxtPath);
        Vaild = false;
        if (!File.Exists(Bin2TxtPath))
        {
            Debug.LogError(Bin2TxtPath + " Not Exists !");
            return;
        }
        else if (EditorSettings.serializationMode == SerializationMode.ForceText)
        {
            Debug.LogError("Only Tested On Project Which SerializationMode is Set to - SerializationMode.ForceText -");
            return;
        }
        ApplicationDataPath = Application.dataPath;
        procosserCount = SystemInfo.processorCount;
        Vaild = true;
    }

    public void BuildRefrenceMap(RefrenceMap map,Action<JobExcuteProgress> updateTitle)
    {
        Assert.IsNotNull(map);
        if (!Vaild)
        {
            Debug.LogError("RefrenceMapBuilder is Not Vaild!");
            return;
        }
        m_curMap = map;
        Stopwatch watch = new Stopwatch();
        watch.Start();
        GC.Collect();

        m_totalFiles = Directory.GetFiles(ApplicationDataPath, "*.*", SearchOption.AllDirectories)
                                .Where(s => nativeReadableExtensions.Contains(Path.GetExtension(s).ToLower()) && !s.Contains("LightingData.asset"))
                                .ToArray();
        Debug.Log("Find File Count " + m_totalFiles.Length);
        GC.Collect();
        watch.Stop();
        Debug.Log("Collect Cost Time " + watch.Elapsed.TotalSeconds + " (s)");

        int core = procosserCount > 16 ? procosserCount - 2 : procosserCount + 2;
        int splitCount = Mathf.Max(1, m_totalFiles.Length / core);
        Debug.Log("splitCount :" + splitCount);

        ParallelTask.BeginParallelTask(core, updateTitle);
        m_curMap.assetPaths = new string[m_totalFiles.Length];
        m_curMap.refrencedGUID = new string[m_totalFiles.Length][];
        ParallelTask.DoParallelFor(m_totalFiles.Length, DoRefrenceCollectInternal, splitCount);
        ParallelTask.EndParallelTask();

        GC.Collect();
    }

    public void DoRefrenceCollectInternal(int index)
    {
        try
        {
            string path = m_totalFiles[index];//.Replace("\\", "/");
            m_curMap.assetPaths[index] = path.Replace(@"\", @"/");

            ThreadableBin2Txt tool = new ThreadableBin2Txt(checkMBThreshold,ApplicationDataPath);
            string[] textAssetLines = tool.ConvertAssetToText(m_totalFiles[index], Bin2TxtPath);
            if (textAssetLines == null)
            {
                Debug.LogError("ConvertAssetToText Result is NULL :" + m_totalFiles[index]);
                return;
            }
            //Look Like This
            //m_Texture: {fileID: 2800000, guid: da6807e903d11d54aba20623695e5762, type: 3}
            List<string> guids = new List<string>();
            for (int j = 0; j < textAssetLines.Length; j++)
            {
                int stringIndex = textAssetLines[j].ToLower().IndexOf("guid:");
                if (stringIndex != -1)
                {
                    string text = textAssetLines[j].Substring(stringIndex + 6, 32);
                    
                    guids.Add(text);
                }
            }
            m_curMap.refrencedGUID[index] = guids.ToArray();
        }
        catch (Exception e)
        {
            Debug.LogError("Error When Excute DoRefrenceCollectInternal \n" + e);
        }


    }
}

